// Point Particle system's shader
var PointPSVertexShaderStr = 
"uniform float local_time;\n" + 
"uniform float time;\n" +
"uniform mat4 view_proj_matrix;\n" +
"uniform mat4 model_matrix;\n" + 
"attribute vec4 in_pos_life;\n" + 
"attribute vec4 in_veloc_time;\n" +
"attribute vec4 in_accel_size;\n" + 
"attribute vec4 in_color;\n"+
"\n" + 
"varying float out_life;\n" +
"varying float started;\n" + 
"varying vec4 out_color;\n" +
"\n" + 
"void main()\n" + 
"{\n" + 
"  vec3 accel = in_accel_size.xyz;\n" + 
"  float time_t = time - local_time - in_veloc_time.w;\n" +
"  started = 1.0;\n" +  
"  if (time_t < 0.0) {\n" +
"    started = 0.0;\n" +
"    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" + 
"    return;\n" +   
"  }\n" + 
"  time_t = mod(time_t, in_pos_life.w);\n" + 
"  out_life = 1.0;\n\/\/in_pos_life.w - time_t;\n" + 
"  vec3 veloc = in_veloc_time.xyz;\n" + 
"  vec3 pos = in_pos_life.xyz + veloc * time_t + accel * time_t * time_t * 0.5;\n" +
"  gl_PointSize = in_accel_size.w;\n" +
"  gl_Position = view_proj_matrix* model_matrix * vec4(pos, 1.0);\n" +
"  out_color = in_color;\n" + 
"}\n";

var PointPSFragmentShaderStr =
"varying float out_life;\n" + 
"varying float started;\n" +
"varying vec4 out_color;\n" +
"\n" + 
"void main()\n" + 
"{\n" + 
"  if (started * out_life <= 0.0) {\n" +
"    discard;\n" +
"  }\n" + 
"  gl_FragColor = out_color;\n" +
"}\n";

// Streak particle system's shader
var StreakPSVertexShaderStr = 
"uniform float local_time;\n" + 
"uniform float time;\n" +
"uniform mat4 view_proj_matrix;\n" +
"uniform mat4 model_matrix;\n" + 
"attribute vec4 in_pos_life;\n" + 
"attribute vec4 in_veloc_time;\n" +
"attribute vec4 in_accel_size;\n" + 
"attribute vec4 in_color;\n"+
"\n" + 
"varying float out_life;\n" +
"varying float started;\n" + 
"varying vec4 out_color;\n" +
"\n" + 
"void main()\n" + 
"{\n" + 
"  vec3 accel = in_accel_size.xyz;\n" + 
"  float time_t = time - local_time - in_veloc_time.w;\n" +
"  started = 1.0;\n" +  
"  if (time_t < 0.0) {\n" +
"    started = 0.0;\n" +
"    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" + 
"    return;\n" +   
"  }\n" + 
"  time_t = mod(time_t, in_pos_life.w)-in_accel_size.w;\n" + 
"  out_life = 1.0;\n\/\/in_pos_life.w - time_t;\n" + 
"  vec3 veloc = in_veloc_time.xyz;\n" + 
"  vec3 pos = in_pos_life.xyz + veloc * time_t + accel * time_t * time_t * 0.5;\n" +
"  gl_Position = view_proj_matrix* model_matrix * vec4(pos, 1.0);\n" +
"  out_color = in_color;\n" + 
"}\n";

// Sprite2D particle system's shader
var Sprite2dPSVertexShaderStr = 
"uniform float local_time;\n" + 
"uniform float time;\n" +
"uniform vec3 right;\n" + 
"uniform vec3 up;\n" + 
"uniform mat4 view_proj_matrix;\n" +
"uniform mat4 model_matrix;\n" + 
"attribute vec4 in_pos_life;\n" + 
"attribute vec4 in_veloc_time;\n" +
"attribute vec4 in_accel_size;\n" + 
"attribute vec2 in_texcoord;\n" +
"attribute vec4 in_color;\n"+
"\n" + 
"varying float out_life;\n" +
"varying float started;\n" + 
"varying vec2 texcoord;\n" +
"varying vec4 out_color;\n" +
"\n" + 
"void main()\n" + 
"{\n" + 
"  vec3 accel = in_accel_size.xyz;\n" + 
"  float time_t = time - local_time - in_veloc_time.w;\n" +
"  time_t /= 1.0;\n" + 
"  started = 1.0;\n" +  
"  if (time_t < 0.0) {\n" + 
"    time_t = mod(-time_t, in_pos_life.w);\n" + 
"    time_t = in_pos_life.w - time_t;\n" + 
"    \/\/started = 0.0;\n" +
"    \/\/gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" + 
"    \/\/return;\n" +   
"  } else {\n" + 
"  time_t = mod(time_t, in_pos_life.w);\n" +
"  }\n" +  
"  out_life = (in_pos_life.w - time_t) / in_pos_life.w;\n" + 
"  vec3 veloc = in_veloc_time.xyz;\n" + 
"  vec3 pos = in_pos_life.xyz + veloc * time_t + accel * time_t * time_t * 0.5;\n" +
"  vec3 out_pos = (model_matrix * vec4(pos, 1.0)).xyz;\n" + 
"  vec3 cam_right = right * in_texcoord.x * in_accel_size.w;\n" + 
"  vec3 cam_up = up * in_texcoord.y * in_accel_size.w;\n" + 
"  out_pos = out_pos + cam_right + cam_up;\n" +  
"  gl_Position = view_proj_matrix * vec4(out_pos, 1.0);\n" +
"  texcoord = clamp(in_texcoord, 0.0, 1.0);\n" +  
"  out_color = in_color;\n" +
"}\n";

var Sprite2dPSFragmentShaderStr = 
"uniform sampler2D sprite_tex;\n" + 
"varying float out_life;\n" + 
"varying float started;\n" +
"varying vec2 texcoord;\n" + 
"varying vec4 out_color;\n" +
"\n" + 
"void main()\n" + 
"{\n" + 
"  if (started * out_life <= 0.0) {\n" +
"    discard;\n" +
"  }\n" + 
"  vec4 color = texture2D(sprite_tex, texcoord);\n" +
"  if (color.a < 0.1) {\n" + 
"    discard;\n" + 
"  }\n" +
"  color.a = out_life;\n"+
"  gl_FragColor = color*out_color;\n" +
"}\n";

function gewParticleEffect(game)
{
  // gl.enable(0x8642);
  this.game = game;
  this.gl = game.gl;
  var gl = this.gl;
  
  this.name = "ParticleEffect";
  this.scene3d = null;
  this.materialList = {};
  this.shaders = {};
  this.shaders.point = {};
  this.shaders.sprite2d = {};
  this.shaders.streak = {};
  // Point particle system shader
  var shader = this.shaders.point;
  shader.vs = null; shader.fs = null; shader.program = null;
  createGLSLShader(gl,shader,PointPSVertexShaderStr,PointPSFragmentShaderStr);
  
  // Sprite2d particle system shader
  var shader = this.shaders.sprite2d;
  shader.vs = null; shader.fs = null; shader.program = null;
  createGLSLShader(gl,shader,Sprite2dPSVertexShaderStr,Sprite2dPSFragmentShaderStr);
  
  // Streak particle system shader
  var shader = this.shaders.streak;
  shader.vs = null; shader.fs = null; shader.program = null;
  createGLSLShader(gl,shader,StreakPSVertexShaderStr,PointPSFragmentShaderStr);  
}

gewParticleEffect.prototype.render = function(scene3d)
{
  var gl = this.gl;
  var game = this.game;
  this.scene3d = scene3d;
  ///////////////////////////////////////////////////////
  // Pass 0: Render Point PS
  this.currentPass = GEW_PS_POINT;
  var shader = this.shaders.point;
  gl.useProgram(shader.program);  
  gl.enableVertexAttribArray(shader.in_pos_life);
  gl.enableVertexAttribArray(shader.in_veloc_time);
  gl.enableVertexAttribArray(shader.in_accel_size);
  gl.enableVertexAttribArray(shader.in_color);
  // Set GL state
  gl.enable(gl.DEPTH_TEST);
  gl.enable(gl.BLEND);
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 
  
  var proj_view_matrix = scene3d.viewProjectMat;
  gl.uniformMatrix4fv(shader.view_proj_matrix, false, proj_view_matrix.data);
  for (var i in this.materialList) {
    this.materialList[i].render();
  }
  //gl.disable(gl.DEPTH_TEST);
  //////////////////////////////////////////////////////////
  // Pass 1 : Render Streak PS
  this.currentPass = GEW_PS_STREAK;
  var shader = this.shaders.streak;
  gl.useProgram(shader.program); 
  
  gl.uniformMatrix4fv(shader.view_proj_matrix, false, proj_view_matrix.data);
  for (var i in this.materialList) {
    this.materialList[i].render();
  }
  
  //////////////////////////////////////////////////////////
  // Pass 2 : Render Sprite2D PS
  this.currentPass = GEW_PS_SPRITE2D;
  var shader = this.shaders.sprite2d;
  gl.useProgram(shader.program);  
  gl.enableVertexAttribArray(shader.in_pos_life);
  gl.enableVertexAttribArray(shader.in_veloc_time);
  gl.enableVertexAttribArray(shader.in_accel_size);
  gl.enableVertexAttribArray(shader.in_color);
  var active_cam = scene3d.camera_system.getActiveCamera();
  var up = active_cam.m_right;
  var right = active_cam.m_up;
  gl.uniform3f(shader.right, right.x, right.y, right.z);
  gl.uniform3f(shader.up, up.x, up.y, up.z);
  // Set GL state
  //gl.enable(gl.DEPTH_TEST);
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
  gl.depthMask(false);
    
  gl.uniformMatrix4fv(shader.view_proj_matrix, false, proj_view_matrix.data);  
  for (var i in this.materialList) {
    this.materialList[i].render();
  }
  
  gl.disableVertexAttribArray(shader.in_pos_life);
  gl.disableVertexAttribArray(shader.in_veloc_time);
  gl.disableVertexAttribArray(shader.in_accel_size);
  gl.disableVertexAttribArray(shader.in_texcoord);
  gl.disableVertexAttribArray(shader.in_color);
  gl.disable(gl.DEPTH_TEST);
  gl.disable(gl.BLEND);
  gl.depthMask(true);
}
